import './styles.css'
import * as THREE from 'three'
import * as dat from "dat.gui";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

//定义渲染器尺寸
const size = {
  width: window.innerWidth,
  height: window.innerHeight,
}

//初始化渲染器 canvas
const canvas = document.querySelector('canvas.webgl')
const renderer = new THREE.WebGLRenderer({ canvas })
renderer.setSize(size.width, size.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

//初始化场景
const scene = new THREE.Scene()

//初始化相机 透视相机 
const camera = new THREE.PerspectiveCamera(45, size.width / size.height, 0.1, 1000)
camera.position.set(0, 0, 150)
camera.lookAt(new THREE.Vector3(0, 0, 0))
scene.add(camera) //场景添加相机


// //添加坐标轴 辅助查看
const axesHelper = new THREE.AxesHelper(150)
scene.add(axesHelper)

//添加轨道 用来用鼠标控制相机
const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true


//加载模型
const rand = (min, max) => min + Math.random() * (max - min);
let astronaut = null
const loader = new GLTFLoader()
loader.load('/models/astronaut.glb', (mesh) => {
  astronaut = mesh.scene
  astronaut.material = new THREE.MeshLambertMaterial()
  astronaut.scale.set(.0005, .0005, .0005)
  astronaut.position.set(0, 0, -10)
  scene.add(astronaut)
})

//加载粒子系统
const geom = new THREE.BufferGeometry()
const material = new THREE.PointsMaterial({
  color: 0xffffff,
  size: 10,
  alphaTest: .8,
  map: new THREE.TextureLoader().load('/images/particle.png')
})
let verticsFloat32Array = []
let verticsColors = []
for (let p = 0; p < 1000; p++) {
  verticsFloat32Array.push(
    rand(20, 30) * Math.cos(p),
    rand(20, 30) * Math.sin(p),
    rand(-1500, 0)
  )
  const randomColor = new THREE.Color(Math.random() * 0xffffff)
  verticsColors.push(randomColor)
}
const vertices = new THREE.Float32BufferAttribute(verticsFloat32Array, 3)
const colors = new THREE.Float32BufferAttribute(verticsColors, 3)
geom.attributes.position = vertices
geom.attributes.color = colors
const particleSystem = new THREE.Points(geom, material)
scene.add(particleSystem)

// 雾化效果
scene.fog = new THREE.FogExp2(0x000000, 0.005);
//  设置光照
let light = new THREE.PointLight(0xFFFFFF, 0.5);
light.position.x = -50;
light.position.y = -50;
light.position.z = 75;
scene.add(light);
light = new THREE.PointLight(0xFFFFFF, 0.5);
light.position.x = 50;
light.position.y = 50;
light.position.z = 75;
scene.add(light);
light = new THREE.PointLight(0xFFFFFF, 0.3);
light.position.x = 25;
light.position.y = 50;
light.position.z = 200;
scene.add(light);
light = new THREE.AmbientLight(0xFFFFFF, 0.02);
scene.add(light);

// Sprite有一定性能问题
// const createParticlesBySprite = () => {
//   for(let x = -15; x < 15; x++) {
//     for(let y = -10; y < 10; y++) {
//       let material = new THREE.SpriteMaterial({
//         color: Math.random() * 0xffffff
//       })
//       let sprite = new THREE.Sprite(material)
//       sprite.position.set(x * 4, y * 4, 0)
//       scene.add(sprite)
//     }
//   }
// }
// createParticlesBySprite()

// const createStyledParticlesByPoints = (ctrls) => {
//   const geom = new THREE.BufferGeometry()
//   const material = new THREE.PointsMaterial({
//     size: ctrls.size,
//     transparent: ctrls.transparent,
//     opacity: ctrls.opacity,
//     vertexColors: ctrls.vertexColors,
//     color: new THREE.Color(ctrls.color),
//     sizeAttenuation: ctrls.sizeAttenuation
//   })
//   let verticsFloat32Array = []
//   let verticsColors = []
//   for (let x = -15; x < 15; x++) {
//     for (let y = -10; y < 10; y++) {
//       verticsFloat32Array.push(x * 4, y * 4, 0)
//       const { r, g, b } = new THREE.Color(Math.random() * ctrls.vertexColor)
//       verticsColors.push(r, g, b)
//     }
//   }
//   const vertices = new THREE.Float32BufferAttribute(verticsFloat32Array, 3)
//   const colors = new THREE.Float32BufferAttribute(verticsColors, 3)
//   geom.attributes.position = vertices
//   geom.attributes.color = colors
//   const particles = new THREE.Points(geom, material)
//   particles.name = 'particles'
//   scene.add(particles)
// }

// // 创建属性控制器
// const ctrls = new function () {
//   this.size = 5;
//   this.transparent = true;
//   this.opacity = 0.6;
//   this.vertexColors = true;
//   this.color = 0xffffff;
//   this.vertexColor = 0x00ff00;
//   this.sizeAttenuation = true;
//   this.rotate = true;
//   this.redraw = function () {
//     if (scene.getObjectByName("particles")) {
//       scene.remove(scene.getObjectByName("particles"));
//     }
//     createStyledParticlesByPoints({
//       size: ctrls.size,
//       transparent: ctrls.transparent,
//       opacity: ctrls.opacity,
//       vertexColors: ctrls.vertexColors,
//       sizeAttenuation: ctrls.sizeAttenuation,
//       color: ctrls.color,
//       vertexColor: ctrls.vertexColor
//     });
//   };
// }
// const gui = new dat.GUI();
// gui.add(ctrls, 'size', 0, 10).onChange(ctrls.redraw);
// gui.add(ctrls, 'transparent').onChange(ctrls.redraw);
// gui.add(ctrls, 'opacity', 0, 1).onChange(ctrls.redraw);
// gui.add(ctrls, 'vertexColors').onChange(ctrls.redraw);
// gui.addColor(ctrls, 'color').onChange(ctrls.redraw);
// gui.addColor(ctrls, 'vertexColor').onChange(ctrls.redraw);
// gui.add(ctrls, 'sizeAttenuation').onChange(ctrls.redraw);

// const createParticlesByGeometry = () => {
//   // 创建发光canvas纹理
//   const generateSprite = () => {
//     const canvas = document.createElement('canvas')
//     const ctx = canvas.getContext('2d')
//     canvas.width = 300
//     canvas.height = 300
//     ctx.lineWidth = 10;
//     ctx.beginPath();
//     ctx.moveTo(170, 120);
//     var grd = ctx.createLinearGradient(0, 0, 170, 0);
//     grd.addColorStop('0', 'black');
//     grd.addColorStop('0.3', 'magenta');
//     grd.addColorStop('0.5', 'blue');
//     grd.addColorStop('0.6', 'green');
//     grd.addColorStop('0.8', 'yellow');
//     grd.addColorStop(1, 'red');
//     ctx.strokeStyle = grd;
//     ctx.arc(120, 120, 50, 0, Math.PI * 2);
//     ctx.stroke();
//     const texture = new THREE.CanvasTexture(canvas)
//     texture.needsUpdate = true
//     return texture
//   }
//   const texture = generateSprite()
// // 创建粒子系统
// const createParticles = (size, transparent, opacity, sizeAttenuation, color) => {
//   const geom = new THREE.BufferGeometry()
//   const material = new THREE.PointsMaterial({
//     size: size,
//     transparent: transparent,
//     opacity: opacity,
//     map: new THREE.TextureLoader().load('/images/heart.png'),
//     sizeAttenuation: sizeAttenuation,
//     color: color,
//     depthTest: true,
//     depthWrite: false
//   })
//   let veticsFloat32Array = []
//   const range = 500
//   for (let i = 0; i < 400; i++) {
//     const particle = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2)
//     veticsFloat32Array.push(particle.x, particle.y, particle.z)
//   }
//   const vertices = new THREE.Float32BufferAttribute(veticsFloat32Array, 3)
//   geom.attributes.position = vertices
//   const particles = new THREE.Points(geom, material)
//   scene.add(particles)
// }
// createParticles(40, true, 1, true, 0xffffff)



// // 创建立方体
// const sphereGeometry = new THREE.SphereGeometry(15, 32, 16);
// // 创建粒子材质
// const material = new THREE.PointsMaterial({
//   color: 0xffffff,
//   size: 3,
//   transparent: true,
//   blending: THREE.AdditiveBlending,
//   map: generateSprite(),
//   depthWrite: false
// })
// const particles = new THREE.Points(sphereGeometry, material)
// scene.add(particles)
// }

// createParticlesByGeometry()

//动画效果
let t = 0
//更新粒子动画
const updateParticles = () => {
  particleSystem.position.x = 0.2 * Math.cos(t)
  particleSystem.position.y = 0.2 * Math.cos(t)
  particleSystem.rotation.z += 0.015
  camera.lookAt(particleSystem.position)
  for (let i = 0; i < verticsFloat32Array.length; i++) {
    // 如果是Z轴值，则修改数值
    if ((i + 1) % 3 === 0) {
      const dist = verticsFloat32Array[i] - camera.position.z;
      if (dist >= 0) verticsFloat32Array[i] = rand(-1000, -500);
      verticsFloat32Array[i] += 2.5;
      const _vertices = new THREE.Float32BufferAttribute(verticsFloat32Array, 3);
      geom.attributes.position = _vertices;
    }
  }
  particleSystem.geometry.verticesNeedUpdate = true
}

//更新宇航员
const updateMeshes = () => {
  if (astronaut) {
    astronaut.position.z = 0.08 * Math.sin(t) + (camera.position.z - 0.2)
    astronaut.rotation.x += 0.015;
    astronaut.rotation.y += 0.015;
    astronaut.rotation.z += 0.01;
  }
}

//更新场景和相机
const updateRenderer = () => {
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
    camera.aspect = canvas.clientWidth / canvas.clientHeight;
    camera.updateProjectionMatrix();
  }
}

// 动态渲染
const tick = () => {
  // controls && controls.update()
  updateParticles()
  updateMeshes()
  updateRenderer()
  renderer.render(scene, camera)
  window.requestAnimationFrame(tick)
  t += 0.01
}
tick()


//页面缩放事件监听  更新渲染器和相机
window.addEventListener('resize', () => {
  size.width = window.innerWidth
  size.height = window.innerHeight
  //渲染器尺寸和像素比更新
  renderer.setSize(size.width, size.height)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  camera.aspect = size.width / size.height
  camera.updateProjectionMatrix() // 手动更新相机对象的投影矩阵属性
})

window.addEventListener('mousemove', e => {
  const cx = window.innerWidth / 2;
  const cy = window.innerHeight / 2;
  const dx = -1 * ((cx - e.clientX) / cx);
  const dy = -1 * ((cy - e.clientY) / cy);
  camera.position.x = dx * 5;
  camera.position.y = dy * 5;
  astronaut.position.x = dx * 5;
  astronaut.position.y = dy * 5;
});